package org.msb.accentis.data.pojo;

import java.math.BigDecimal;
import java.util.Currency;

import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;

import org.msb.accentis.data.enumerations.AccountType;

/**
 * The {@code Account} class provides the ability to manage objects are used to represent bank, credit card, and investment accounts. Accounts are used to
 * group transactions, so that their amounts can be added up and reported as a balance.
 * 
 * @author Marc Boudreau
 * 
 * @since 1.0
 */
@Entity
@NamedQueries({ @NamedQuery(name = "Account.getAllAccounts", query = "SELECT a FROM Account a ORDER BY a.name"),
		@NamedQuery(name = "Account.getAccountById", query = "SELECT a FROM Account a WHERE a.id = :accountId"),
		@NamedQuery(name = "Account.getAllAccountsForType", query = "SELECT a FROM Account a WHERE a.accountType = :type ORDER BY a.name"),
		@NamedQuery(name = "Account.getAllAccountsReferencingInstitution", query = "SELECT a FROM Account a WHERE a.institution = :institution") })
public class Account extends NamedObject {

	@Enumerated(EnumType.ORDINAL)
	private AccountType accountType;

	@Basic
	private BigDecimal startingBalance;

	@Basic
	private BigDecimal minimumBalance;

	@Basic
	private String accountNumber;

	@Basic
	private Currency accountCurrency;

	@ManyToOne
	private Institution institution;

	@Basic
	private boolean closed;

	/**
	 * Returns an instance of the {@link AccountType} enumeration that describes the type of this account.
	 * 
	 * @return A {@link AccountType} instance.
	 */
	public AccountType getAccountType() {
		return accountType;
	}

	/**
	 * Sets the type of this account to the specified {@link AccountType} instance.
	 * 
	 * @param value
	 *            The {@link AccountType} instance to set as this account's type.
	 */
	public void setAccountType(AccountType value) {
		accountType = value;
	}

	/**
	 * Returns the starting balance set for this account. This amount is the balance of the account before any transaction amounts are tabulated.
	 * 
	 * @return The starting balance as a {@link BigDecimal} object.
	 */
	public BigDecimal getStartingBalance() {
		return startingBalance;
	}

	/**
	 * Sets the starting balance amount for this account to the provided {@link BigDecimal} object.
	 * 
	 * @param value
	 *            A {@link BigDecimal} object that represents the amount to set as the starting balance.
	 */
	public void setStartingBalance(BigDecimal value) {
		startingBalance = value;
	}

	/**
	 * Returns the minimum balance set for this account. This is an amount that's used to flag that account if its balance falls below it.
	 * 
	 * @return The minimum balance as a {@link BigDecimal} object.
	 */
	public BigDecimal getMinimumBalance() {
		return minimumBalance;
	}

	/**
	 * Sets the minimum balance amount for this account to the provided {@link BigDecimal} object.
	 * 
	 * @param value
	 *            A {@link BigDecimal} object that represents the amount to set as the minimum balance.
	 */
	public void setMinimumBalance(BigDecimal value) {
		minimumBalance = value;
	}

	/**
	 * Returns this account's number as a {@link String} object. The account number is represented as a {@link String} object because account numbers can often
	 * include non-numerical characters, such as dashes or letters.
	 * 
	 * @return The account number as a {@link String} object.
	 */
	public String getNumber() {
		return accountNumber;
	}

	/**
	 * Sets the account number for this account to the provided {@link String} object.
	 * 
	 * @param value
	 *            A {@link String} object that represents the account number.
	 */
	public void setNumber(String value) {
		accountNumber = value;
	}

	/**
	 * Returns the {@link Institution} object associated to this account.
	 * 
	 * @return The associated {@link Institution} object, or {@code null} if no institution has been associated to this account.
	 */
	public Institution getInstitution() {
		return institution;
	}

	/**
	 * Associates this account with the provided institution.
	 * 
	 * @param value
	 *            The {@link Institution} object to associate.
	 */
	public void setInstitution(Institution value) {
		institution = value;
	}

	/**
	 * Returns the currency of this account.
	 * 
	 * @return A {@link Currency} object representing this account's currency, or null if no specific currency has been associated with this account.
	 */
	public Currency getCurrency() {
		return accountCurrency;
	}

	/**
	 * Sets a specific currency for this account.
	 * 
	 * @param currency
	 *            The {@link Currency} object to associate.
	 */
	public void setCurrency(Currency currency) {
		accountCurrency = currency;
	}

	/**
	 * Indicates whether this account has been marked as closed. Closed accounts can no longer accept transactions, but continue to appear in reports.
	 * 
	 * @return The value of the closed flag as a {@code boolean} value.
	 */
	public boolean isClosed() {
		return closed;
	}

	/**
	 * Sets the value of the closed flag to the provided {@code boolean} value.
	 * 
	 * @param value
	 *            The {@code boolean} value to set as the closed flag value.
	 */
	public void setClosed(boolean value) {
		closed = value;
	}
}
